using System;
using System.Collections.Generic;
using InfiniTec.Exchange.Notifications.Microsoft.Exchange.WebServices;


namespace InfiniTec.Exchange.Notifications
{
	public static class NotificationTypeExtension
	{
		public static IEnumerable<EventInfo> ConvertEvents(this NotificationType notification)
		{
			for (int i = 0; i < notification.Items.Length; i++)
			{
				ItemsChoiceType eventType = notification.ItemsElementName[i];
				BaseNotificationEventType notificationEvent = notification.Items[i];

				var baseModifiedEvent = notificationEvent as BaseObjectChangedEventType;
				var modifiedEvent = notificationEvent as ModifiedEventType;
				var movedCopiedEvent = notificationEvent as MovedCopiedEventType;

				if (eventType == ItemsChoiceType.StatusEvent)
				{
					yield return EventInfo.ForStatusEvent(notificationEvent.Watermark);
				}

				if (eventType != ItemsChoiceType.DeletedEvent && baseModifiedEvent != null)
				{
					var deleteEventFound = false;
					for (int j = 0; j < notification.Items.Length; j++)
					{
						var secondEvent = (BaseObjectChangedEventType)notification.Items[j];
						if (notification.ItemsElementName[j] == ItemsChoiceType.DeletedEvent &&
						    GetItemReference(secondEvent.Item) == GetItemReference(baseModifiedEvent.Item))
						{
							deleteEventFound = true;
							break;
						}
					}
					if (deleteEventFound) continue;
				}

				if (movedCopiedEvent != null)
				{
					yield return EventInfo.ForCopyOrMoveEvent(eventType == ItemsChoiceType.CopiedEvent ? EventType.Copied : EventType.Moved,
					                                          new FolderReference(movedCopiedEvent.ParentFolderId), GetItemReference(movedCopiedEvent.Item),
					                                          new FolderReference(movedCopiedEvent.OldParentFolderId),
					                                          GetItemReference(movedCopiedEvent.Item1), movedCopiedEvent.TimeStamp,
					                                          movedCopiedEvent.Watermark);
				}
				else if (modifiedEvent != null)
				{
					FolderReference folderId = GetFolderReference(modifiedEvent.Item);
					if (folderId != null)
					{
						yield return EventInfo.ForModifiedEvent(new FolderReference(modifiedEvent.ParentFolderId),
						                                        folderId, modifiedEvent.TimeStamp,
						                                        (modifiedEvent.UnreadCountSpecified) ? (int?)modifiedEvent.UnreadCount : null, modifiedEvent.Watermark);
					}
					else
					{
						yield return EventInfo.ForModifiedEvent(new FolderReference(modifiedEvent.ParentFolderId),
						                                        GetItemReference(modifiedEvent.Item), modifiedEvent.TimeStamp,
						                                        modifiedEvent.Watermark);
					}
				}
				else if (baseModifiedEvent != null)
				{
					EventType type;
					switch (eventType)
					{
						case ItemsChoiceType.CreatedEvent:
							type = EventType.Created;
							break;
						case ItemsChoiceType.DeletedEvent:
							type = EventType.Deleted;
							break;
						case ItemsChoiceType.NewMailEvent:
							type = EventType.NewMail;
							break;
						default:
							throw new InvalidOperationException(string.Format("The eventType {0} is not supported with a baseModifiedEvent", eventType));

					}
					yield return EventInfo.ForNewOrDeletionEvent(type, new FolderReference(baseModifiedEvent.ParentFolderId), GetItemReference(baseModifiedEvent.Item),
					                                             baseModifiedEvent.TimeStamp, baseModifiedEvent.Watermark);

				}
			}
		}

		private static ItemReference GetItemReference(object item)
		{
			var itemId = item as ItemIdType;
			return (itemId != null) ? new ItemReference(itemId) : null;
		}

		private static FolderReference GetFolderReference(object folder)
		{
			var folderIdType = folder as BaseFolderIdType;
			return (folderIdType != null) ? new FolderReference(folderIdType) : null;
		}
	}
}